import numexpr

import charmicat.event_filter
import charmicat.utils        

def build_cut_list(module, opts):
    cut_list = []

    # opts.by_name
    # opts.cutsets
    # opts.by_cl
    # opts.exclude
    # opts.replace
    # opts.start_on
    # opts.intersection

    if len(opts.list) > 0:
        cut_list = opts.list 
        
        if len(opts.cutsets) > 0:
            cut_list += [name for cutset_name in opts.cutsets for name in module.cutsets[cutset_name]]
            

    elif len(opts.cutsets) > 0:
        cut_list = [name for cutset_name in opts.cutsets for name in module.cutsets[cutset_name]]
                    
    else:
        name = module.cutsets['__default__']
        
        if type(name) == type('yo'):
            opts.cutsets = [name]
        else:
            opts.cutsets = name
            
        cut_list = [name for cutset_name in opts.cutsets for name in module.cutsets[cutset_name]]
            
    if len(opts.replace) > 0:
        replacement_dict = dict(opts.replace)

        for i in xrange(len(cut_list)):
            if cut_list[i] in replacement_dict:
                cut_list[i] = replacement_dict[cut_list[i]]

    if opts.start_on is not None:
        try:
            index = cut_list.index(opts.start_on)
        except ValueError:
            msg = "`--start-on={0}' supplied, but cut named `{0}' not found in cut list:\n"
            msg = "\t" + str(cut_list) 
            raise charmicat.utils.BadCommandLineError(msg, -102)
            
        cut_list = cut_list[index:]


    if len(opts.exclude) > 0:
        for name in opts.exclude:
            try:
                cut_list.remove(name)
            except ValueError:
                msg = "Exclude cut `{0}'; cut not found in list. "
                msg += "Present values are: {1}"
                raise charmicat.utils.BadCommandLineError(msg.format(name, cut_list), -103)

    try:        
        cuts = [module.cuts[name] for name in cut_list]
    except KeyError:
        msg = "No cut named `{0}' found in `{1}.cuts'.\n".format(name, module.__name__)
        raise charmicat.utils.BadCommandLineError(msg, -104)


    if opts.intersection:
        cuts = [cut_intersection(cuts)]

        name = 'intersection of '
        if len(opts.cutsets) > 0:
            name += ' '.join(opts.cutsets) 
        if len(opts.list) > 0:
            name += ' '.join(opts.list)

        cuts[0].name = name

        
    return cuts


def cut_intersection(cutseq, name=None, desc=None):
    if name is None:
        name = 'intersection of '
        name += ' and '.join([c.name for c in cutseq])

    pos_str = ' & '.join(['({0})'.format(cut.pos_str) for cut in cutseq])

    condvars = {}
    for c in cutseq:
        condvars.update(c.condvars)

    return charmicat.event_filter.Cut(name=name,
                                      pos_str=cut_intersection_str(cutseq),
                                      desc=desc,
                                      condvars=condvars)
    

def cut_intersection_str(cut_seq):
    try:
        return ' & '.join(['({0})'.format(cut.pos_str) for cut in cut_seq])
    except AttributeError:
        return ' & '.join(['({0})'.format(cut) for cut in cut_seq])

def cut_accumulate(cut_seq):
    for i in xrange(len(cut_seq)):
        yield cut_intersection_str(cut_seq[:i+1])

def which_kills(cutset, rows, colnames):
    ret = [None]*len(rows)
    rdict = dict([(col, rows[col]) for col in colnames])
    for c in cutset:
        rdict.update(c.condvars)
        res = numexpr.evaluate(c.pos_str, local_dict=rdict)
        for i in xrange(len(res)):
            if not res[i] and ret[i] is None:
                ret[i] = c.name
        
    return ret



__all__ = "build_cut_list cut_intersection cut_accumulate which_kills".split()
